/* ==============================================================================
*
*   Copyright (c) 2010, Pierre Favier
*   All rights reserved.
*
*   NTasking is free software: you can redistribute it and/or modify it
*   under the terms of the GNU General Public License as published by the
*   Free Software Foundation.
*
*   Redistribution and use in source and binary forms, with or without
*   modification, are permitted provided that the following conditions
*   are met:
*
*   -   Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*
*   -   Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials
*       provided with the distribution.
*
*   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
*   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
*   BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
*   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
*   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
*   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
*   THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*   SUCH DAMAGE.
*
* ============================================================================== */

using System;
using NUnit.Framework;
using Rhino.Mocks;
using Rhino.Mocks.Constraints;

namespace NTasking.ValidationTests.Other.SyntaxErrors
{

    [TestFixture]
    public class Tasks : ValidationTest
    {

        internal class SelfCallingTask : ValidationTestTask
        {
            [Entry]
            internal Action AnEntry { get; private set; }

            internal SelfCallingTask(IValidationTestResult result)
                : base(result)
            {}


            protected override void Body()
            {
                AnEntry();
            }
            protected override void Exception(Exception ex)
            {
                if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.SelfEntryCallError)
                    Result.TestFailed();
            }
        }


        [Test]
        public void SelfEntryCall()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            SelfCallingTask task;

            Ada.Declare(() =>
            {
                task = new SelfCallingTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class NullSelectTask : ValidationTestTask
        {
            [Entry]
            internal Action AnEntry { get; private set; }

            internal NullSelectTask(IValidationTestResult result)
                : base(result)
            { }


            protected override void Body()
            {
                Select(null);
            }
            protected override void Exception(Exception ex)
            {
                if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.StatementsIsNullError)
                    Result.TestFailed();
            }
        }


        [Test]
        public void SelectStatementsNull()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            NullSelectTask task;

            Ada.Declare(() =>
            {
                task = new NullSelectTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class AcceptInAbortablePartTask : ValidationTestTask
        {
            [Entry]
            internal Action AnEntry { get; private set; }

            internal AcceptInAbortablePartTask(IValidationTestResult result)
                : base(result)
            { }


            protected override void Body()
            {
                Ada.Select(s => s.
                    Delay(1.0).
                ThenAbort(() =>
                {
                    Accept(AnEntry);
                }));
            }
            protected override void Exception(Exception ex)
            {
                if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptNotAllowedInAbortablePartError)
                    Result.TestFailed();
            }
        }


        [Test]
        public void AcceptInAbortablePart()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptInAbortablePartTask task;

            Ada.Declare(() =>
            {
                task = new AcceptInAbortablePartTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class SelectInAbortablePartTask : ValidationTestTask
        {
            [Entry]
            internal Action AnEntry { get; private set; }

            internal SelectInAbortablePartTask(IValidationTestResult result)
                : base(result)
            { }


            protected override void Body()
            {
                Ada.Select(s => s.
                    Delay(1.0).
                ThenAbort(() =>
                {
                    Select(s2 => s2.
                        Accept(AnEntry).
                    Or.
                        Terminate);
                }));
            }
            protected override void Exception(Exception ex)
            {
                if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.SelectNotAllowedInAbortablePartError)
                    Result.TestFailed();
            }
        }


        [Test]
        public void SelectInAbortablePart()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            SelectInAbortablePartTask task;

            Ada.Declare(() =>
            {
                task = new SelectInAbortablePartTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class AcceptWithNullBodyTask : ValidationTestTask
        {
            [Entry]
            internal Func<bool> AnEntry { get; private set; }

            [Entry]
            internal FuncFamily<int, bool> AnEntryFamily { get; private set; }

            internal AcceptWithNullBodyTask(IValidationTestResult result)
                : base(result)
            { }


            protected override void Body()
            {
                try
                {
                    Accept(AnEntry, null);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.BodyIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(AnEntryFamily[0], null);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.BodyIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(AnEntry, null).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.BodyIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(AnEntryFamily[0], null).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.BodyIsNullError)
                        Result.TestFailed();
                }

            }
        }


        [Test]
        public void AcceptBodyIsNull()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptWithNullBodyTask task;

            Ada.Declare(() =>
            {
                task = new AcceptWithNullBodyTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class AcceptWithSynchBodyTask : ValidationTestTask
        {
            [Entry]
            internal Func<bool> AnEntry { get; private set; }

            [Entry]
            internal Func<bool> AnEntryBody { get; private set; }

            [Entry]
            internal FuncFamily<int, bool> AnEntryFamily { get; private set; }

            [Entry]
            internal Func<int, bool> AnEntryFamilyBody { get; private set; }

            internal AcceptWithSynchBodyTask(IValidationTestResult result)
                : base(result)
            { }


            protected override void Body()
            {
                try
                {
                    Accept(AnEntry, AnEntryBody);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptBodyIsSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(AnEntryFamily[0], AnEntryFamilyBody);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptBodyIsSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(AnEntry, AnEntryBody).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptBodyIsSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(AnEntryFamily[0], AnEntryFamilyBody).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptBodyIsSynchronizedError)
                        Result.TestFailed();
                }

            }
        }


        [Test]
        public void AcceptWithSynchBody()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptWithSynchBodyTask task;

            Ada.Declare(() =>
            {
                task = new AcceptWithSynchBodyTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class AcceptNotSynchronizedTask : ValidationTestTask
        {

            internal AcceptNotSynchronizedTask(IValidationTestResult result)
                : base(result)
            { }


            private void AnEntry()
            {
            }


            private void ABody(int param)
            {
            }


            protected override void Body()
            {
                Action anEntry = AnEntry;
                Action<int> aBody = ABody;

                try
                {
                    Accept(anEntry);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(anEntry, aBody);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(anEntry).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotSynchronizedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(anEntry, aBody).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotSynchronizedError)
                        Result.TestFailed();
                }

            }
        }


        [Test]
        public void AcceptNotSynchronized()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptNotSynchronizedTask task;

            Ada.Declare(() =>
            {
                task = new AcceptNotSynchronizedTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class OtherTask : Task
        {
            [Entry]
            internal Action AnEntry { get; private set; }

            [Entry]
            internal ActionFamily<int> AnEntryFamily { get; private set; }

            protected override void Body()
            {
            }
        }


        internal class AcceptNotOwnedTask : ValidationTestTask
        {

            private readonly OtherTask _other;


            internal AcceptNotOwnedTask(IValidationTestResult result, OtherTask other)
                : base(result)
            {
                _other = other;
            }


            private void ABody(int param)
            {
            }


            protected override void Body()
            {
                Action<int> aBody = ABody;

                try
                {
                    Accept(_other.AnEntry);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(_other.AnEntryFamily);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(_other.AnEntryFamily[0]);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(_other.AnEntry).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(_other.AnEntryFamily).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(_other.AnEntryFamily[0]).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.AcceptCallNotOwnedError)
                        Result.TestFailed();
                }

            }
        }


        [Test]
        public void AcceptNotOwned()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptNotOwnedTask task;
            OtherTask other;

            Ada.Declare(() =>
            {
                other = new OtherTask();
                task = new AcceptNotOwnedTask(result, other);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }


        internal class AcceptNullEntryTask : ValidationTestTask
        {

            internal AcceptNullEntryTask(IValidationTestResult result)
                : base(result)
            {
            }


            private void ABody(int param)
            {
            }


            protected override void Body()
            {
                Action anEntry = null;
                ActionFamily<int> aFamily = null;
                Action<int> aBody = ABody;

                try
                {
                    Accept(anEntry);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(aFamily);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Accept(anEntry, aBody);
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(anEntry).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(aFamily).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

                try
                {
                    Select(s => s.
                        Accept(anEntry, aBody).
                    Or.
                        Terminate
                    );
                }
                catch (Exception ex)
                {
                    if (!(ex is SyntaxError) || ((SyntaxError)ex).ErrorCode != Errors.EntryIsNullError)
                        Result.TestFailed();
                }

            }
        }


        [Test]
        public void AcceptNullEntry()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            AcceptNullEntryTask task;

            Ada.Declare(() =>
            {
                task = new AcceptNullEntryTask(result);

                // Setup text expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
            },
            Exception: (ex) =>
            {
                // Unexpected exception thrown
                result.TestFailed();

                return false;
            });
        }

    }

}
